/**
Tests about closures, and safe invokes importants link for this part :
- http://fandev.org/doc/docLang/Closures.html
- http://fandev.org/doc/docLang/Functions.html
- http://fandev.org/doc/docLang/Expressions.html#safeInvoke

This code is volontary not full Object Oriented
*/

class Main
{
  static const Str empty := "unknown"

  //  func parameter is a function that takes a person and return void (ouf !)
  static Void testFun (Str testName, |Person? -> Void| func , Person? [] pl){
    echo("Test on : $testName")
    pl.each |Person? p|{
      func.call(p)
    }
    echo("")
  }

  static Void main()
  {
    gainsbourg := Person ("Serge", "Gainsourg")
    birkin  := Person ("Jane", "Birkin"){ 
      age = 56
      father = gainsbourg
    }


    // use It-Blocks to make a specific person 
    // Is equivalent to create a person, then use 3 set methods
    charlotte := Person ("Charlotte", "Gainsourg"){
      age = 34
      father = gainsbourg
      mother = birkin
    }

    
    /*** Closure test  - BEGINING ***/
    test1   := "Closure - begining (to beeeee continued)"
    people1 := Person[gainsbourg,birkin,charlotte]
    f1      := |Person p|{ // |Person p| is equivalent to |Person p-> Void|
      living := (p.age != null)? "${p.age} years old" : "dead"
      echo ("\tHello, I'm $p.firstName $p.lastName and i'm ${living}.")
    }
    testFun(test1,f1,people1)
    /*** Closure test  - END ***/


    /*** Safe Invokes + Binding  - BEGINING ***/
    test2   := "Operations on null pointers (safe calls)"
    people2 := Person?[gainsbourg,birkin,charlotte,null]
    f2      := |Person? p|{
      if (p != null) 
        f1(p); // Here f2 use f1 despites f1 is local, it's called "binding"
      else
        echo ("$empty person found");
      echo ("\tMy father's name is ${p?.father?.firstName ?: empty}.")
    }
    testFun(test2,f2,people2)
    /*** Safe Invokes + Binding  - END ***/


    /*** More tests ***/
    // Peoples who have father
    hasAFather := |Person? p -> Bool|{return (p?.father != null)}
    pplWithF :=  people2.findAll(hasAFather)
    echo ("Peoples who have a father :")
    pplWithF.each |Person p| { f1(p) }
    // Keep not null only
    echo ("Peoples who exists :")
    people2.findType(Person#).each{ f1(it) }
    // Alive people
    echo ("Alive people :")
    people2.findAll(|Person? p->Bool|{p?.age!=null}).each{ f1(it) }
    // Stupid test
    echo ("Je suis fou,".padr(15,'F').replace("FFF","! kcuF ".reverse.lower).upper)

  }
}


